package com.haizhi.crm.sys.auth.service.impl;

import com.haizhi.crm.common.constant.SysStatus;
import com.haizhi.crm.common.exception.UnexpectedStatusException;
import com.haizhi.crm.common.log.GLog;
import com.haizhi.crm.common.log.LogFactory;
import com.haizhi.crm.common.model.Response;
import com.haizhi.crm.common.util.CommonUtils;
import com.haizhi.crm.common.util.Md5SaltUtils;
import com.haizhi.crm.common.util.PasswordEncrypt;
import com.haizhi.crm.sys.auth.constant.AuthConstant;
import com.haizhi.crm.sys.auth.dao.*;
import com.haizhi.crm.sys.auth.model.*;
import com.haizhi.crm.sys.auth.service.UserService;
import com.haizhi.crm.sys.shiro.ChainDefinitionProvider;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * Created by chengmo on 2018/5/15.
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {

    private static final GLog LOG = LogFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Autowired
    private ChainDefinitionProvider chainDefinitionProvider;
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private ResourceDao resourceDao;
    @Autowired
    private DepartmentDao departmentDao;
    @Autowired
    private RelationItemDao relationItemDao;

    @Override
    public Response save(UserQo userQo) {
        try {
            String signature = userQo.getSignature();
            userQo.setSignature(null);
            String localSignature = Md5SaltUtils.getEncrypted(userQo.toString());
            if (localSignature.equals(signature)) {
                //1.upsert user info to table ts_user
                upsertUserInfo(userQo);
                //2.upsert user role info to table tr_user_role
                upsertUserRoleInfo(userQo);
                return Response.success();
            } else {
                throw new UnexpectedStatusException(SysStatus.SYNC_USER_ERROR);
            }
        } catch (Exception e) {
            LOG.error("sync user info error", e);
            throw new UnexpectedStatusException(SysStatus.SYNC_USER_ERROR, e);
        }
    }

    @Override
    public Response detail() {
        Long userId = CommonUtils.getUserID();
        try {
            UserVo userVo = userDao.findBy(userId);
            Long deptId = departmentDao.findByManagerId(CommonUtils.getUserID());
            if (deptId != null) {
                userVo.setManager(true);
            }
            return Response.success(userVo);
        } catch (Exception e) {
            throw new UnexpectedStatusException(SysStatus.USER_QUERY_ERROR, e, userId);
        }
    }

    @Override
    public Response updatePassword(UpdatePasswordQo updatePasswordQo) {
        try {
            UserDo userDo = userDao.findOne(CommonUtils.getUserID());
            if (null == userDo) {
                throw new UnexpectedStatusException(SysStatus.USER_NOTEXISTS);
            }
            String dbPassword = userDo.getPassword();
            boolean success = PasswordEncrypt.matchPassword(updatePasswordQo.getOldPassword(), dbPassword);
            if (success) {
                String newPassword = PasswordEncrypt.buildEncryptPassword(updatePasswordQo.getNewPassword());
                userDo.setPassword(newPassword);
                userDao.save(userDo);
            } else {
                throw new UnexpectedStatusException(SysStatus.OLD_PASSWD_MISMATCH);
            }
            return Response.success();
        } catch (UnexpectedStatusException e) {
            throw new UnexpectedStatusException(e.getStatus(), e);
        } catch (Exception e) {
            throw new UnexpectedStatusException(SysStatus.UPDATE_PASSWD_ERROR, e);
        }
    }

    public void reloadPermission() {

        synchronized (shiroFilterFactoryBean) {
            AbstractShiroFilter shiroFilter = null;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            } catch (Exception e) {
                throw new RuntimeException(
                        "get ShiroFilter from shiroFilterFactoryBean error!" );
            }

            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
                    .getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
                    .getFilterChainManager();

            manager.getFilterChains().clear();

            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean
                    .setFilterChainDefinitionMap(chainDefinitionProvider.getAllRolesPermissions());
            Map<String, String> chains = shiroFilterFactoryBean
                    .getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim()
                        .replace(" ", "" );
                manager.createChain(url, chainDefinition);
            }
        }
    }

    @Override
    public Response findPermissions(Long parentId, String companyKey) {
        try {
            Long userId = CommonUtils.getUserID();
            //如果是超级管理员，则不走权限
            if (AuthConstant.SUPER_ADMIN.equals(String.valueOf(userId))) {
                List<ResourceVo> resourceVos = ResourceVo.buildResourceTreeFromDo(resourceDao.findAll());
                return getResponse(parentId, resourceVos);
            }
            //不是客户详情页时
            if (StringUtils.isBlank(companyKey)) {
                List<ResourceVo> resourceVos = resourceDao.findByUserId(userId);
                return getResponse(parentId, resourceVos);
            } else {//是客户详情页时
                //岗位权限
                List<ResourceVo> positionResources = resourceDao.findPositionResourcesByUserId(userId);

                //关系权限
                List<Long> relationIds = relationItemDao.findBy(userId, companyKey);
                if (CollectionUtils.isEmpty(relationIds)) {
                    return getResponse(parentId, positionResources);
                }
                List<ResourceVo> relationResources = resourceDao.findRelationResourcesBy(userId, relationIds.toArray(new Long[relationIds.size()]));
                positionResources.addAll(relationResources);

                Map<Long, ResourceVo> resMap = new HashMap<>();
                List<ResourceVo> resourceVos = new ArrayList<>();
                positionResources.forEach(resourceVo -> {
                    if (!resMap.containsKey(resourceVo.getId())) {
                        resMap.put(resourceVo.getId(), resourceVo);
                        resourceVos.add(resourceVo);
                    }
                });
                return getResponse(parentId, resourceVos);
            }
        } catch (Exception e) {
            throw new UnexpectedStatusException(SysStatus.USER_RELOAD_PERMISSION_FAIL, e);
        }
    }

    private Response getResponse(Long parentId, List<ResourceVo> resourceVos) {
        List<ResourceVo> resourceTreeVos = ResourceVo.buildResourceTree(resourceVos);
        List<ResourceVo> result = new ArrayList<>();
        for (ResourceVo resourceVo : resourceTreeVos) {
            if (parentId.equals(resourceVo.getId())) {
                result.add(resourceVo);
                return Response.success(result);
            }
        }
        return Response.success(new ArrayList<>());
    }

    @Override
    public Response findByName(String name) {
        try {
            return Response.success(userDao.findByName(name));
        } catch (Exception e) {
            throw new UnexpectedStatusException(SysStatus.FIND_USERS_ERROR, e);
        }
    }

    @Override
    public Response confirmPassword(String password) {
        try {
            UserDo userDo = userDao.findOne(CommonUtils.getUserID());
            if (null == userDo) {
                throw new UnexpectedStatusException(SysStatus.USER_NOTEXISTS);
            }
            String dbPassword = userDo.getPassword();
            boolean success = PasswordEncrypt.matchPassword(password, dbPassword);
            if (success) {
                return Response.success();
            } else {
                return Response.error();
            }
        } catch (UnexpectedStatusException e) {
            LOG.error(SysStatus.CONFIRM_PWD_ERROR.getDesc(), e);
        }
        return Response.error();
    }

    ///////////////////////
    // private functions
    ///////////////////////

    private void upsertUserRoleInfo(UserQo userQo) {
        List<UserRoleDo> userRoleDos = userRoleDao.findByUserId(userQo.getUserId());
        if (CollectionUtils.isEmpty(userRoleDos)) {
            UserRoleDo userRoleDo = new UserRoleDo();
            userRoleDo.setUserId(userQo.getUserId());
            userRoleDo.setRoleId(userQo.getPositionId());
            userRoleDao.save(userRoleDo);
        } else {
            UserRoleDo userRoleDo = userRoleDos.get(0);
            if (!userRoleDo.getRoleId().equals(userQo.getPositionId())) {
                userRoleDo.setRoleId(userQo.getPositionId());
                userRoleDao.save(userRoleDo);
            }
        }
    }

    private void upsertUserInfo(UserQo userQo) {
        UserDo userDo = new UserDo();
        userDo.setId(userQo.getUserId());
        userDo.setUpdatedDt(new Date());
        userDo.setEnabledFlag(userQo.getEnabledFlag());
        userDo.setDepartmentId(userQo.getDepartmentId());
        userDo.setExtensionNo(userQo.getExtensionNo());
        userDo.setIdNumber(userQo.getIdNumber());
        userDo.setName(userQo.getName());
        userDo.setPositionId(userQo.getPositionId());
        userDo.setStatus(userQo.getStatus());
        userDo.setType(userQo.getType());
        userDo.setUserNo(userQo.getUserNo());
        UserDo u = userDao.findOne(userQo.getUserId());
        if (null == u) {
            userDo.setPassword(PasswordEncrypt.buildEncryptPassword("123456" ));
            userDo.setCreatedDt(new Date());
        } else {
            userDo.setPassword(u.getPassword());
        }
        userDao.save(userDo);
    }

}
